package network

import (
	"fmt"
	"net"
	"operator/pkg/codes/tcp"
	"strconv"
	"sync"
	"time"
)

type TcpServer struct {
	mu       sync.RWMutex
	list     map[string]*NetStatus
	listener *net.TCPListener
	dictFn   map[string]func([]byte) []byte
}

func (ts *TcpServer) listen() {
	conn, err := ts.listener.Accept()
	if err != nil {
		return
	}
	ts.mu.Lock()
	defer ts.mu.Unlock()

	status := NewNetStatus(conn, time.Second*20)
	ts.list[conn.RemoteAddr().String()] = status

	go ts.dealConn(conn)
}

func (ts *TcpServer) dealConn(conn net.Conn) {
	buffer := make([]byte, 1024*30)
	for {
		n, err := conn.Read(buffer)
		if err != nil {
			break
		}

		data := tcp.Decode(buffer[:n])
		if data.Tag().IsResponse() {

		} else {
			if fn, ok := ts.dictFn[data.Tag().String()]; ok {
				res := fn(data.Data())
				resdata := data.ResponseData(res)
				_, err = conn.Write(resdata.ToBytes())
				if err != nil {
					break
				}
			}
		}
	}
}

func (ts *TcpServer) Write(addr, tag string, data []byte) {
	if conn, ok := ts.list[addr]; ok {
		d := tcp.Encode(tag, data)
		err := conn.Write(d.ToBytes())
		if err != nil {
			fmt.Println(err)
		}
	}
}

func (ts *TcpServer) BroadCast(tag string, data []byte) {
	d := tcp.Encode(tag, data)
	for _, conn := range ts.list {
		err := conn.Write(d.ToBytes())
		if err != nil {
			fmt.Println(err)
			continue
		}
	}
}

func (ts *TcpServer) Run(stopCh <-chan struct{}) {
	for {
		select {
		case <-stopCh:
			break
		default:
			ts.listen()
		}
	}
}

func (ts *TcpServer) AddFn(tag string, fn func([]byte) []byte) {
	ts.dictFn[tag] = fn
}

func NewTcpServer(port int) (*TcpServer, error) {
	addr, err := net.ResolveTCPAddr("tcp", ":"+strconv.Itoa(port))
	if err != nil {
		return nil, err
	}
	listener, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return nil, err
	}

	tcp := &TcpServer{
		list:     map[string]*NetStatus{},
		listener: listener,
		mu:       sync.RWMutex{},
		dictFn:   map[string]func([]byte) []byte{},
	}

	return tcp, nil
}
